package com.mamingchao.basic.bit;

public class BitOperation {

    public static void main(String[] args) {
        final int a = 26;
        final int b = 39;
        // System.out.println(getBiggerOne(a, b));
        // System.out.println("结果=" + is4Power(b));
        System.out.println("结果=" + multiply(a, b));
    }

    /**
     * 给定两个有符号32位整数a和b,返回a和b中较大的。
     *  【要求】
     *   不用做任何比较判断。
     * 思路：通过位运算获取a和b的符号位，然后根据符号位进行判断。
     * @param a
     * @param b
     * @return 其中一个较大值
     */
    private static int getBiggerOne(int a, int b){
        // 通过位运算判断a与b的符号位是否相同
         // 计算差值的符号位
         // 0 : a > b
         // 1 : a < b
        int diffSign = (a - b) >> 31;
        // 利用符号位选择：如果差值为负，返回b；否则返回a
        // 以下两种方式都可以
        return (b & diffSign) + (a & ~diffSign);
        // return b & diffSign | a & ~diffSign;
    }

    /**
     * 判断一个32位正数是不是2的幂
     */
    private static boolean is2Power(int num){
        if (num < 2) {
            return false;
        }

        return (num & (num - 1)) == 0;
    }

    /**
     * 判断一个32位正数是不是4的幂
     */
    private static boolean is4Power(int num){
        if (num < 4) {
            return false;
        }

        // 是4的幂，那么一定需要显示2的幂
        if (!is2Power(num)) {
            return false;
        }

        // 如果已经是2的幂，即二进制数据，有且只有一个1，那么就两位两位的看
        while(num !=0) {
            num = num >>> 2;
            if ((num ^ 4) == 0) {
                return true;
            }

        }

        // 如果一个数要是4的幂，那一定是这个样子010101....010100
        // 所以，这个num ^ 010101....010100 == 0,说明 那num 就一定也是 010101....010100
        // 异或操作为无进位相加

        return false;
    }

    /*
     * 给定两个有符号32位整数a和b,不能使用算术运算符,分别实现a和b的加、减、乘、除运算
        【要求】
        如果给定a、b执行加减乘除的运算结果就会导致数据的溢出,那么你实现的函数不必对此
        负责,除此之外请保证计算过程不发生溢出

        加法：1、a与b异或是无进位相加；2、想办法计算进位信息；如果计算出进位信息，并与a与b的无进位相加结果 相加，则得出答案 3、进位信息与 a与b异或的无进位相加结果相加，又是加法运算；继续走1,2步骤的过程
              一直转，直到有一步骤（经过试验确实是这样），进位信息会变成0
        减法：1、b 取反 2、 走加法的逻辑
        
        除法：1、a与b异或；2、进位与b与a与b的与运算；3、循环直到进位为0

     */
    private static int add(int a, int b){
        while(b != 0) {
            // temp 为 a与b无进位相加的结果
            int temp = a ^ b;
            // 此时b为进位信息
            b = (a & b) << 1;
            // 最后一次循环走到这里，b为0，无进位相加的结果就是结果
            a = temp;
        }
        return a;
    }
    

    /**
     * 7 取反 ==-8
     * 8取反 == -9
     * 所以要取反后再加1，或者 减一后再取反
     * 我们加法是现成的，所以用先取反再加1
     */
    private static int minus(int a, int b){
        int negNum = add(~b, 1);
        return add(a, negNum);
    }


    /**
     * 二进制乘法与10进制一样
     *          011010
     *        * 100111 
     *        -----------
     *         011010
     *        011010
     *       011010
     *      000000
     *     000000
     *    011010  
     * -----------
     *  以上累加和
     */
    private static int multiply(int a , int b){
        int c = 0;
        while(b != 0) {
            // b&1 == 1 说明b的最后一位是1
            if ((b & 1) == 1) {
                a = add(a, c);
            }
            c = (c==0 ? a : c) << 1;
            // b右移一位，相当于除以2
            b = b >> 1;
        }
        return a;
    }

    private static int divide(int a , int b){
        return 0;
    }
}
